package com.sy.simpleegg.serialport

import com.sy.simpleegg.bean.CashConfigBean
import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.coincontroller.CoinController
import com.sy.simpleegg.serialport.coincontroller.bean.CoinControlFixParam
import com.sy.simpleegg.serialport.sycontroller.SyBusinessController
import com.sy.simpleegg.serialport.sycontroller.bean.CoinControlParam
import com.sy.simpleegg.serialport.whmandroid.WhmAndroidCoinController
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidParam
import com.sy.simpleegg.serialport.whmlyy.WhmLyyController
import com.sy.simpleegg.serialport.whmlyy.bean.WhmLyyParam
import com.sy.simpleegg.util.GsonUtil

class CoinManager(
    private val coinControlParam: CoinControlParam?,
    private val coinControlFixParam: CoinControlFixParam?,
    private val whmLyyParam: WhmLyyParam?,
    private val whmAndroidParam: WhmAndroidParam?,
    private val onCoinListener: OnCoinListener
) {

    private var coinController: SyBusinessController? = null
    private var fixController: CoinController? = null
    private var transferController: WhmLyyController? = null
    private var whmAndroidCoinController: WhmAndroidCoinController? = null

    private var outCoinOrderNumber = ""
    private var saveCoinOrderNumber = ""

    init {
        coinControlParam?.let {
            initCoinControl(it)
        }

        coinControlFixParam?.let {
            initCoinControlFix(it)
        }

        whmLyyParam?.let {
            initTransferController(it)
        }

        whmAndroidParam?.let {
            initWhmAndroidController(it)
        }
    }

    private fun initCoinControl(param: CoinControlParam){
        try {
            param.run {
                coinController = SyBusinessController(
                portName, baudrate, stopb, datab, parity, runHeartBeat, speed
            )
            coinController?.setSerialControllerListener(object :
                SyBusinessController.SerialControllerListener {
                override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
                    onCoinListener.heartBeat(isConnect, stateCode, errCode)
                }

                override fun countErr(count: Long) {
                    onCoinListener.countErr(outCoinOrderNumber, count)
                }

                override fun motorTimeout(motorNumber: Int) {
                    onCoinListener.motorTimeout(outCoinOrderNumber, motorNumber)
                }

                override fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long) {
                    onCoinListener.onClearCoin(outCoinOrderNumber, clearFinish, clearCoinCount)
                }

                override fun outCoinFinish(
                    remainCount: Long,
                    currentOutCount: Long,
                    outFinish: Boolean
                ) {
                    onCoinListener.outCoinFinish(outCoinOrderNumber, remainCount, currentOutCount, outFinish)
                }

                override fun onMotorErr(motorNumber: Int) {
                    onCoinListener.onMotorErr(outCoinOrderNumber, motorNumber)
                }

                override fun saveCoinFinish(count: Long) {
                    onCoinListener.saveCoinFinish(saveCoinOrderNumber, count)
                }

                override fun onCoinRefresh(coinCount: Long, outOrSave: Boolean) {
                    if (outOrSave){
                        onCoinListener.onCoinRefresh(outCoinOrderNumber , -1, coinCount, outOrSave)
                    }
                }
            })
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("启动硬币控制板异常")
        }
    }

    private fun initCoinControlFix(param: CoinControlFixParam){
        try {
            param.run {
                fixController = CoinController(
                    portName, baudrate, stopb, datab, parity, runHeartBeat, verNumber, speed
                ).apply {
                    setSerialControllerListener(object : CoinController.SerialControllerListener{
                        override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
                            onCoinListener.heartBeat(isConnect, stateCode, errCode)
                        }

                        override fun countErr(count: Long) {
                            onCoinListener.countErr(outCoinOrderNumber, count)
                        }

                        override fun motorTimeout(motorNumber: Int) {
                            onCoinListener.motorTimeout(outCoinOrderNumber, motorNumber)
                        }

                        override fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long) {
                            onCoinListener.onClearCoin(outCoinOrderNumber, clearFinish, clearCoinCount)
                        }

                        override fun outCoinFinish(
                            remainCount: Long,
                            currentOutCount: Long,
                            outFinish: Boolean
                        ) {
                            onCoinListener.outCoinFinish(outCoinOrderNumber, remainCount, currentOutCount, outFinish)
                        }

                        override fun onMotorErr(motorNumber: Int) {
                            onCoinListener.onMotorErr(outCoinOrderNumber, motorNumber)
                        }

                        override fun saveCoinFinish(count: Long) {
                            onCoinListener.saveCoinFinish(saveCoinOrderNumber, count)
                        }

                        override fun onCoinRefresh(coinCount: Long, needOutCoins: Long, outOrSave: Boolean) {
                            val coins = if (outOrSave){
                                needOutCoins - coinCount
                            }else{
                                coinCount
                            }
                            onCoinListener.onCoinRefresh(if (outOrSave) outCoinOrderNumber else saveCoinOrderNumber, needOutCoins, coins, outOrSave)
                        }

                        override fun onOutRec() {
                            onCoinListener.onOutRec()
                        }

                        override fun onOutResult(msg: String) {
                            onCoinListener.onOutResult(msg)
                        }
                    })
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("启动硬币控制板Fix异常")
        }
    }

    private fun initTransferController(param: WhmLyyParam){
        try {
            param.run {
                transferController = WhmLyyController(
                    portName, baudrate, stopb, datab, parity, runHeartBeat,
                    object : WhmLyyController.WhmLyyListener{
                        override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
                            onCoinListener.heartBeat(isConnect, stateCode, errCode)
                        }

                        override fun onRecCash(
                            addCode: Int,
                            errCodeHex: String,
                            cash: String,
                            outCoins: String,
                            donateCoins: String,
                            descHex: String
                        ) {
                            logFile("未处理-账目上报数据：自增码=$addCode 故障代码=$errCodeHex 现金=$cash 出币数=$outCoins 增币数=$donateCoins 预留数据=$descHex")
                            if (cash.isNotEmpty() && cash != "0"){
                                onCoinListener.onRecCashData(cash.toLong()*100, outCoins.toLong())
                            }
                        }

                        override fun onRecBasicConfig(configHex: String) {
                            logFile("获取基础配置：$configHex")
                            onCoinListener.onRecBasicConfig(configHex)
                        }

                        override fun onRecCashConfig(configHex: String) {
                            logFile("获取纸钞配置：$configHex")
                            onCoinListener.onRecCashConfig(configHex)
                        }

                        override fun onRecMotorConfig(configHex: String) {
                            logFile("获取马达配置：$configHex")
                            onCoinListener.onRecMotorConfig(configHex)
                        }

                        override fun onCoinRefresh(needOutCoins: Long, coinCount: Long, outOrSave: Boolean) {
                            onCoinListener.onCoinRefresh(if (outOrSave) outCoinOrderNumber else saveCoinOrderNumber, needOutCoins, coinCount, outOrSave)
                        }

                        override fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long) {
                            onCoinListener.onClearCoin(outCoinOrderNumber, clearFinish, clearCoinCount)
                        }

                        override fun outCoinFinish(
                            remainCount: Long,
                            currentOutCount: Long,
                            outFinish: Boolean
                        ) {
                            onCoinListener.outCoinFinish(outCoinOrderNumber, remainCount, currentOutCount, outFinish)
                        }

                        override fun saveCoinFinish(
                            saveCoins: Long,
                            snHex: String,
                            userIdHex: String,
                        ) {
                            onCoinListener.saveCoinFinish(saveCoinOrderNumber, saveCoins)
                        }

                        override fun onOutResult(msg: String) {
                            onCoinListener.onOutResult(msg)
                        }

                        override fun onCmdTimeout(comData: ComData) {
                            logFile("指令超时：${GsonUtil.getInstance()!!.toJson(comData)}")
                        }

                        override fun onSendCmd(msg: String) {
//                            logFile("发送数据：$msg")
                        }
                    }
                )
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("启动中转控制板异常")
        }
    }

    private fun initWhmAndroidController(param: WhmAndroidParam){
        try {
            param.run {
                whmAndroidCoinController = WhmAndroidCoinController(
                    cashType,
                    portName,
                    baudrate,
                    stopb,
                    datab,
                    parity,
                    true,
                    1,
                    50
                ).apply {
                    setSerialControllerListener(object : WhmAndroidCoinController.SerialControllerListener{
                        override fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int) {
                            onCoinListener.heartBeat(isConnect, stateCode, errCode)
                        }

                        override fun countErr(count: Long) {
                            onCoinListener.countErr(outCoinOrderNumber, count)
                        }

                        override fun motorTimeout(motorNumber: Int) {
                            onCoinListener.motorTimeout(outCoinOrderNumber, motorNumber)
                        }

                        override fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long) {
                            onCoinListener.onClearCoin(outCoinOrderNumber, clearFinish, clearCoinCount)
                        }

                        override fun outCoinFinish(
                            remainCount: Long,
                            currentOutCount: Long,
                            outFinish: Boolean
                        ) {
                            logFile("出币结束 remainCount=$remainCount currentOutCount=$currentOutCount")
                            onCoinListener.outCoinFinish(outCoinOrderNumber, remainCount, currentOutCount, outFinish)
                        }

                        override fun onMotorErr(motorNumber: Int) {
                            onCoinListener.onMotorErr(outCoinOrderNumber, motorNumber)
                        }

                        override fun saveCoinFinish(count: Long) {
                            onCoinListener.saveCoinFinish(saveCoinOrderNumber, count)
                        }

                        override fun onCoinRefresh(coinCount: Long, remainCoins: Long, outOrSave: Boolean) {
                            onCoinListener.onCoinRefresh(if (outOrSave) outCoinOrderNumber else saveCoinOrderNumber, coinCount, remainCoins, outOrSave)
                        }

                        override fun onOutRec() {
                            logFile("控制板响应收到出币指令")
                        }

                        override fun onOutResult(msg: String) {
                            logFile(msg)
                        }

                        override fun onBanknoteResp(stateHex: String, cashDataHex: String) {
                            logFile("纸钞数据：$cashDataHex")
                        }

                        override fun onMotorConfigResp(
                            forwardTimeoutHex: String,
                            reverseTimeoutHex: String,
                            stopDelayHex: String
                        ) {
                            onCoinListener.onMotorConfigResp(forwardTimeoutHex, reverseTimeoutHex, stopDelayHex)
                        }

                        override fun getMoney1(checkMoney: Long, totalMoney: Long) {
                            onCoinListener.onGetMoney1(checkMoney, totalMoney)
                        }

                        override fun recieveMoney1(tempMoney: Long, checkMoney: Long) {
//                            onCoinListener.onRecieveMoney1(checkMoney, tempMoney)
                            onCoinListener.onRecieveMoney1(tempMoney, checkMoney)
                        }

                        override fun getMoney2(checkMoney: Long, totalMoney: Long) {
                            onCoinListener.onGetMoney2(checkMoney, totalMoney)
                        }

                        override fun recieveMoney2(tempMoney: Long, checkMoney: Long) {
                            onCoinListener.onRecieveMoney2(tempMoney, checkMoney)
                        }

                        override fun onDispenser1Resp(coins: Long) {
                            onCoinListener.onInCoin1(coins)
                        }

                        override fun onDispenser2Resp(coins: Long) {
                            onCoinListener.onInCoin2(coins)
                        }

                        override fun onDispenser1SaveResp(coins: Long) {
                            onCoinListener.onSaveCoin1(saveCoinOrderNumber, coins)
                        }

                        override fun onDispenser2SaveResp(coins: Long) {
                            onCoinListener.onSaveCoin2(saveCoinOrderNumber, coins)
                        }

                        override fun onInCoins(coins1: Long, coins2: Long) {
                            onCoinListener.onInCoin(coins1, coins2)
                        }
                    })
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("打开whm_android出币控制板异常：${e.message}")
        }
    }

    fun getConnectState(): Boolean{
        coinController?.let {
            return it.getConnectState()
        }
        fixController?.let {
            return it.getConnectState()
        }
        transferController?.let {
            return it.getConnectState()
        }
        whmAndroidCoinController?.let {
            return it.getConnectState()
        }
        return false
    }

    fun outCoinM1Business(orderNumber: String, coins: Long){
        outCoinOrderNumber = orderNumber
        coinController?.outCoinM1Business(coins)
        fixController?.outCoinM1Business(coins)
        transferOutCoins(coins)
        whmAndroidCoinController?.outCoinM1Business(coins, coins*100)
    }

    fun outCoinM2Business(orderNumber: String, coins: Long){
        outCoinOrderNumber = orderNumber
        coinController?.outCoinM2Business(coins)
        fixController?.outCoinM2Business(coins)
        transferOutCoins(coins)
        whmAndroidCoinController?.outCoinM2Business(coins, coins*100)
    }

    fun outCoinAlternately(orderNumber: String, coins: Long){
        outCoinOrderNumber = orderNumber
        coinController?.outCoinAlternately(coins)
        fixController?.outCoinAlternately(coins)
        transferOutCoins(coins)
        whmAndroidCoinController?.outCoinAlternately(coins, coins*100)
    }

    fun doubleOutCoinBusiness(orderNumber: String, coins: Long){
        outCoinOrderNumber = orderNumber
        coinController?.doubleOutCoinBusiness(coins)
        fixController?.outCoinAlternately(coins)
        transferOutCoins(coins)
        whmAndroidCoinController?.outCoinAlternately(coins, coins*100)
    }

    fun clearCoinAlternately(){
        coinController?.clearCoinAlternately()
        fixController?.clearCoinAlternately()
        transferController?.clearCoins()
        whmAndroidCoinController?.clearCoinAlternately()
    }

    fun startInMoney(isStart: Boolean){
        logFile("${if (isStart) "开启" else "关闭"}进钞")
        whmAndroidCoinController?.startInMoney(1, isStart)
    }

    /**
     * 接收纸钞
     * @param isSave true-接收 false-拒绝
     */
    fun canSaveMoney(isSave: Boolean){
//        banknoteController?.canSaveMoney(isSave)
        whmAndroidCoinController?.canSaveMoney(1, isSave)
    }

    fun setBasicConfig(basicConfigHex: String){
        transferController?.setBasicConfig(basicConfigHex)
    }

    fun getBasicConfig(){
        transferController?.getTerminalConfig()
    }

    fun getCashConfig(){
        transferController?.getCashConfig()
    }

    fun setCashConfig(cashConfigBean: CashConfigBean){
        transferController?.setCashConfig(cashConfigBean)
    }

    fun getMotorConfig(){
        transferController?.getMotorConfig()
    }

    fun setMotorConfig(forward: Int, reverse: Int, stopDelay: Int){
        transferController?.setMotorConfig(forward, reverse, stopDelay)
    }

    fun setTransOutMode(mode: Int){
        val resultMode = when (mode){
            0 -> {
                //马达1
                1
            }
            1 -> {
                //马达2
                2
            }
            else -> {
                //双马达
                0
            }
        }
        transferController?.setMode(resultMode)
    }

    fun openDispenser(d1: Boolean, d2: Boolean){
        transferController?.openDispenser(d1, d2)
    }

    fun setDispenserProportion(proportion1: Int, proportion2: Int){
        transferController?.setDispenserProportion(proportion1, proportion2)
    }

    fun openBanknote(b1: Boolean, b2: Boolean){
        transferController?.openBanknote(b1, b2)
    }

    fun setCashProportion(proportion: Int){
        transferController?.setCashProportion(proportion)
    }

    fun setCashCountry(country: Int){
        transferController?.setCashCountry(country)
    }

    /**
     * 中转控制板出币，不需要区分马达出币模式
     */
    private fun transferOutCoins(coins: Long){
        transferController?.let {
            val sn = it.getSn()
            val uniqueCode = it.unRepeatSixCode()
            it.outCoins(coins, coins*100, sn, uniqueCode)
        }
    }

    fun saveCoinEnable(orderNumber: String, userId: String, open: Boolean){
        saveCoinOrderNumber = if (open) orderNumber else ""
        if (open) {
            transferController?.saveCoins(orderNumber, userId)
        }else{
            transferController?.saveFinish()
        }
        whmAndroidCoinController?.saveCoins(open)
    }


    fun resetMotor(){
        transferController?.resetMotor()
        whmAndroidCoinController?.resetMotor()
    }

    fun release(){
        coinController?.release()
        fixController?.release()
        transferController?.release()
        whmAndroidCoinController?.release()
    }

    interface OnCoinListener{
        fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int)

        fun countErr(orderNumber: String, count: Long)

        fun motorTimeout(orderNumber: String, motorNumber: Int)

        fun onClearCoin(orderNumber: String, clearFinish: Boolean, clearCoinCount: Long)

        fun outCoinFinish(
            orderNumber: String,
            remainCount: Long,
            currentOutCount: Long,
            outFinish: Boolean
        )

        fun onMotorErr(orderNumber: String, motorNumber: Int)

        fun saveCoinFinish(orderNumber: String, count: Long)

        fun onCoinRefresh(orderNumber: String, coinCount: Long, remainCount: Long, outOrSave: Boolean)

        fun onOutRec()

        fun onOutResult(msg: String)

        fun onRecCashData(cash: Long, coins: Long)

        fun onRecBasicConfig(basicConfigHex: String)

        fun onRecCashConfig(cashConfigHex: String)

        fun onRecMotorConfig(cashConfigHex: String)

        fun onMotorConfigResp(forwardTimeoutHex: String, reverseTimeoutHex: String, stopDelayHex: String)

        fun onGetMoney1(checkMoney: Long, totalMoney: Long)

        fun onRecieveMoney1(tempMoney: Long, checkMoney: Long)

        fun onGetMoney2(checkMoney: Long, totalMoney: Long)

        fun onRecieveMoney2(tempMoney: Long, checkMoney: Long)

        fun onInCoin1(coins: Long)

        fun onInCoin2(coins: Long)

        fun onSaveCoin1(orderNumber: String, coins: Long)

        fun onSaveCoin2(orderNumber: String, coins: Long)

        fun onInCoin(coins1: Long, coins2: Long)
    }
}